package com.example.mfbq.arithmetic;

import android.os.Bundle;
import android.os.Message;

import com.example.mfbq.handler.ArithmeticHandler;

public class SJFArithmetic {
    private Process[] processes;
    private ProcessQueue queue = new ProcessQueue(0);
    private ArithmeticHandler handler;

    public SJFArithmetic(Process[] processes, ArithmeticHandler handler){
        this.processes = processes;
        this.handler = handler;
        sortProcess();
    }

    //非抢占式
    private Process continueProcess;
    private int delay;
    public void start(){
        int current = 0;
        delay = 0;
        while (true){
            Process p = hasProcess(current);
            if(p != null){//如果有新进程到来先放入队列
                this.queue.add(p);
                //更新界面
                Message msg = new Message();
                msg.what = 0x112;//代表要更新队列区
                msg.arg1 = 0;//代表更新第0号队列
                msg.arg2 = p.getProcessId();//代表队列区加入的内容
                msg.obj = "add";
                handler.sendMessageDelayed(msg, delay*1000);
                delay++;
            }
            Process executePro = null;//代表这个单位时间将要执行的进程
            if(continueProcess == null){//代表上一个进程这个时间点已经执行完了
                executePro = getExecuteProcess();
            }else{//代表上一个进程现在还没有执行完，继续执行（非抢占）
                executePro = continueProcess;
            }
            if(handDownProcess() == false){
                break;
            }else{
                if(executePro == null){
                    Message leisure = new Message();
                    leisure.what = 0x114;
                    handler.sendMessageDelayed(leisure, delay*1000);
                    delay++;

                    current++;
                    continue;
                }else{
                    Message msg = new Message();
                    msg.what = 0x111;
                    msg.arg1 = executePro.getProcessId();
                    msg.arg2 = current;
                    handler.sendMessageDelayed(msg, delay*1000);
                    delay++;

                    executePro.setDoneTime(executePro.getDoneTime() + 1);
                    if(executePro.getDoneTime() == executePro.getServeTime()){
                        executePro.setCompleteTime(current + 1);
                        continueProcess = null;

                        Message message = new Message();
                        message.what = 0x123;
                        message.arg1 = executePro.getProcessId();
                        message.arg2 = current + 1;
                        handler.sendMessageDelayed(message, delay*1000);
                        delay++;
                    }else{
                        continueProcess = executePro;
                    }
                }
            }
            current++;
        }
        sortByEnd();
        Message result = new Message();
        result.what = 0x213;
        Bundle data = new Bundle();
        data.putString("arithmetic", "sjf");
        data.putString("result", toResultString());
        data.putDouble("art", getAverageRevolveTime());
        data.putDouble("awrt", getWAverageRevolveTime());
        result.obj = processes;
        result.setData(data);
        handler.sendMessageDelayed(result, delay*1000);
    }

    //抢占式
    private Process cProcess;
    public void startFight(){
        int current = 0;
        delay = 0;
        while (true){
            Process p = hasProcess(current);
            Process executePro = null;//代表这个单位时间将要执行的进程
            if(p != null){
                if(cProcess != null){
                    int t1 = cProcess.getServeTime() - cProcess.getDoneTime();
                    int t2 = p.getServeTime() - p.getDoneTime();
                    if(t2 < t1){
                        this.queue.add(cProcess);
                        //更新界面
                        Message fight = new Message();
                        fight.what = 0x211;//代表要更新队列区
                        fight.arg1 = cProcess.getQueueId();//代表更新队列
                        fight.arg2 = cProcess.getProcessId();//代表队列区加入的内容
                        fight.obj = p.getProcessId();
                        Bundle data = new Bundle();
                        data.putInt("time", current);
                        data.putInt("f", 1);
                        data.putInt("reTime", p.getServeTime());
                        fight.setData(data);
                        handler.sendMessageDelayed(fight, delay*1000);
                        delay++;

                        cProcess = null;
                        executePro = p;
                    }else{
                        this.queue.add(p);
                        //更新界面
                        Message msg = new Message();
                        msg.what = 0x112;//代表要更新队列区
                        msg.arg1 = 0;//代表更新第0号队列
                        msg.arg2 = p.getProcessId();//代表队列区加入的内容
                        msg.obj = "add";
                        handler.sendMessageDelayed(msg, delay*1000);
                        delay++;
                    }
                }else{
                    this.queue.add(p);
                    //更新界面
                    Message msg = new Message();
                    msg.what = 0x112;//代表要更新队列区
                    msg.arg1 = 0;//代表更新第0号队列
                    msg.arg2 = p.getProcessId();//代表队列区加入的内容
                    msg.obj = "add";
                    handler.sendMessageDelayed(msg, delay*1000);
                    delay++;
                }
            }

            if(executePro == null){
                if(cProcess == null){//代表上一个进程这个时间点已经执行完了
                    executePro = getExecuteProcessShort(current);
                }else{//代表上一个进程现在还没有执行完，继续执行
                    executePro = cProcess;
                }
            }

            if(handDownProcess() == false){
                break;
            }else{
                if(executePro == null){

                    Message leisure = new Message();
                    leisure.what = 0x114;
                    handler.sendMessageDelayed(leisure, delay*1000);
                    delay++;

                    current++;
                    continue;
                }else{

                    Message msg = new Message();
                    msg.what = 0x111;
                    msg.arg1 = executePro.getProcessId();
                    msg.arg2 = current;
                    handler.sendMessageDelayed(msg, delay*1000);
                    delay++;

                    executePro.setDoneTime(executePro.getDoneTime() + 1);
                    if(executePro.getDoneTime() == executePro.getServeTime()){
                        executePro.setCompleteTime(current + 1);
                        cProcess = null;

                        Message message = new Message();
                        message.what = 0x123;
                        message.arg1 = executePro.getProcessId();
                        message.arg2 = current + 1;
                        handler.sendMessageDelayed(message, delay*1000);
                        delay++;
                    }else{
                        cProcess = executePro;
                    }
                }
            }
            current++;
        }
        sortByEnd();
        Message result = new Message();
        result.what = 0x213;
        Bundle data = new Bundle();
        data.putString("arithmetic", "sjf");
        data.putBoolean("fight", true);
        data.putString("result", toResultString());
        data.putDouble("art", getAverageRevolveTime());
        data.putDouble("awrt", getWAverageRevolveTime());
        result.obj = processes;
        result.setData(data);
        handler.sendMessageDelayed(result, delay*1000);
    }

    //获取队列中服务时间最短的进程
    private Process getExecuteProcess(){
        int length = this.queue.size();
        Process pro = this.queue.poll();
        for(int i=1;i<length;i++){
            Process pro1 = this.queue.poll();
            if(pro1.getServeTime() < pro.getServeTime()){
                this.queue.add(pro);
                pro = pro1;
            }else{
                this.queue.add(pro1);
            }
        }

        if(pro != null){
            Message msg = new Message();
            msg.what = 0x112;
            msg.arg1 = 0;
            msg.arg2 = pro.getProcessId();
            msg.obj = "remove";
            Bundle data = new Bundle();
            data.putString("content", "队列中"+pro.getProcessId()+"号进程服务时间最短，为 "+pro.getServeTime());
            msg.setData(data);
            handler.sendMessageDelayed(msg, delay*1000);
            delay++;
        }
        return pro;
    }

    //获取队列中剩余服务时间最短的进程
    private Process getExecuteProcessShort(int current){
        int length = this.queue.size();
        Process pro = this.queue.poll();
        for(int i=1;i<length;i++){
            Process pro1 = this.queue.poll();
            int s1 = pro1.getServeTime() - pro1.getDoneTime();
            int s2 = pro.getServeTime() - pro.getDoneTime();
            if(s1 < s2){
                this.queue.add(pro);
                pro = pro1;
            }else{
                this.queue.add(pro1);
            }
        }
        if(pro != null){
            int sy = pro.getServeTime()-pro.getDoneTime();
            Message msg = new Message();
            msg.what = 0x112;
            msg.arg1 = 0;
            msg.arg2 = pro.getProcessId();
            msg.obj = "remove";
            Bundle data = new Bundle();
            data.putString("content", "队列中"+pro.getProcessId()+"号进程剩余服务时间最短，为 "+sy);
            msg.setData(data);
            handler.sendMessageDelayed(msg, delay*1000);
            delay++;
        }
        return pro;
    }

    //按照进程到达时间排序
    private void sortProcess(){
        Process[] pro = this.processes;
        Process process = new Process();//用于作为交换媒介
        for(int i = 0; i < pro.length; i++){
            for(int j = 0; j < pro.length - 1 - i; j++){
                if(pro[j].getComeTime() > pro[j+1].getComeTime()){
                    process = pro[j];
                    pro[j] = pro[j+1];
                    pro[j+1] = process;
                }
            }
        }
    }
    //按进程结束时间排序
    private void sortByEnd(){
        Process[] pro = this.processes;
        Process process;
        for(int i = 0; i < pro.length; i++){
            for(int j = 0; j < pro.length - 1 - i; j++){
                if(pro[j].getCompleteTime() > pro[j+1].getCompleteTime()){
                    process = pro[j];
                    pro[j] = pro[j+1];
                    pro[j+1] = process;
                }
            }
        }
    }
    //判断队列中是否还有进程
    private boolean handDownProcess(){
        for(Process p : this.processes){
            if(p.getDoneTime() != p.getServeTime()){
                return true;
            }
        }
        return false;
    }
    //判断这一时刻是否有进程到来，有进程到来返回进程对象，无进程到来返回null
    private Process hasProcess(int currentTime){
        for(Process p : this.processes){
            if(p.getComeTime() == currentTime){
                return p;
            }
        }
        return null;
    }

    //得到平均周转时间
    private double getAverageRevolveTime(){
        int sum = 0;
        for(Process p : this.processes){
            sum = sum + p.getRevolveTime();
        }
        return ((double)sum) / this.processes.length;
    }
    //得到平均带权周转时间
    private double getWAverageRevolveTime(){
        double sum = 0.0;
        for(Process p : this.processes){
            sum = sum + p.getwRevolveTime();
        }
        return sum/this.processes.length;
    }
    //显示数据
    private String toResultString() {
        String str = "";
//        for(Process p : this.processes){
//            str = str + p.toString() + "\n";
//        }
        str = str + "平均周转时间为："+String.format("%.3f", getAverageRevolveTime())+"\n";
        str = str + "平均带权周转时间为："+String.format("%.3f", getWAverageRevolveTime());
        return str;
    }
}